package com.andova.toolkit.net;

import android.content.Context;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import androidx.annotation.NonNull;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by Zsago on 2017/2/9.
 *
 * @since 2.0.1
 */
public abstract class BaseMockNetwork implements Interceptor {
    private Context mContext;
    private Retrofit retrofit;
    private MockNetworkProvider mProvider;

    private final String CHARSET_NAME_UTF8 = "UTF-8";

    public BaseMockNetwork(String url, Context context, MockNetworkProvider provider) {
        this.mContext = context;
        this.mProvider = provider;

        //定义Http Client,并添加拦截器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(this)
                .build();

        //设置Http Client
        retrofit = new Retrofit.Builder()
                .baseUrl(url.endsWith("/") ? url : url + "/")
                .addConverterFactory(GsonConverterFactory.create())
                .client(okHttpClient)
                .build();
    }

    /**
     * 进行模拟网络数据请求
     */
    public <ResponseModel> ResponseModel request() {
        try {
            return mProvider.mockResponse(create(), readAssetFile(mContext, mProvider.responseFileName(), CHARSET_NAME_UTF8).toString());
        } catch (ClassCastException | NullPointerException e) {
            e.printStackTrace();
        }
        return null;
    }

    private StringBuilder readAssetFile(Context context, String filePath, String charsetName) {
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder fileContent = new StringBuilder();
        try {
            is = context.getAssets().open(filePath);
            br = new BufferedReader(new InputStreamReader(is, charsetName));
            String lineContent;
            while ((lineContent = br.readLine()) != null) {
                fileContent.append(lineContent);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert is != null;
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                assert br != null;
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fileContent;
    }

    private StringBuilder readAssetFile(String filePath, String charsetName) {
        File file = new File(filePath);
        StringBuilder fileContent = new StringBuilder("");
        if (!file.isFile()) {
            return null;
        }

        BufferedReader reader = null;
        try {
            InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);
            reader = new BufferedReader(is);
            String line;
            while ((line = reader.readLine()) != null) {
                fileContent.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fileContent;
    }

    @SuppressWarnings("unused")
    private String getResponseString(String fileName) {
        StringBuilder sb = readAssetFile(mContext + fileName, CHARSET_NAME_UTF8);
        if (sb == null) return "";
        return sb.toString();
    }

    @SuppressWarnings("unchecked")
    private <NetworkInterfaceAPI> NetworkInterfaceAPI create() {
        try {
            return (NetworkInterfaceAPI) retrofit.create(networkInterface());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * OKHttp3.x获取post请求参数body的方式
     */
    private String getRequestString(Request request) throws IOException {
        RequestBody requestBody = request.body();
        assert requestBody != null;
        Buffer buffer = new Buffer();
        requestBody.writeTo(buffer);
        Charset charset = Charset.forName(CHARSET_NAME_UTF8);
        MediaType contentType = requestBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(charset);
        }
        assert charset != null;
        return buffer.readString(charset);
    }

    /**
     * 读文件获取json字符串，生成ResponseBody
     */
    private String createResponseBody(Chain chain) throws IOException {
        if (mProvider == null) return null;
        String request = getRequestString(chain.request());
        System.out.println("" + request.contains(mProvider.requestString()));

        return readAssetFile(mContext, mProvider.responseFileName(), CHARSET_NAME_UTF8).toString();
    }

    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        String respString = createResponseBody(chain);
        if (respString == null) return null;
        return new Response.Builder()
                .code(200)
                .message(respString)
                .request(chain.request())
                .protocol(Protocol.HTTP_1_0)
                .body(ResponseBody.create(MediaType.parse("application/json"), respString.getBytes()))
                .addHeader("content-type", "application/json")
                .build();
    }

    public interface MockNetworkProvider {
        String requestString();

        String responseFileName();

        <ResponseModel, NetworkInterfaceAPI> ResponseModel mockResponse(NetworkInterfaceAPI netApi, String data);
    }

    abstract <NetworkInterfaceAPI> Class<NetworkInterfaceAPI> networkInterface();
}
